﻿#include "ksff.h"



#ifdef WIN32


namespace ksff
{

 

typedef void  (__cdecl  *__TFUNCFOUNDFILEA)( const CHAR*  lpszFileName, void* pUserData );
typedef void  (__cdecl  *__TFUNCFOUNDFILEW)( const WCHAR* lpszFileName, void* pUserData );

BOOL  __searchFilesA(const CHAR* lpszFileName, __TFUNCFOUNDFILEA  lpSearchFunc, void* pUserData,   BOOL bInnerFolders )
{
	LPSTR part;
	char tmp[MAX_PATH]; 
	char name[MAX_PATH];

	HANDLE hSearch = NULL;
	WIN32_FIND_DATAA  afd ;
	memset(&afd, 0, sizeof(WIN32_FIND_DATAA));


	if(bInnerFolders)
	{
		if(GetFullPathNameA(lpszFileName, MAX_PATH, tmp, &part) == 0) 
		{  
			return FALSE; 
		}

		strcpy(name, part);
		strcpy(part, "*.*");

		afd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
		if (!((hSearch = FindFirstFileA(tmp, &afd)) == INVALID_HANDLE_VALUE))
			do
			{
				if (!strncmp(afd.cFileName, ".", 1) || !strncmp(afd.cFileName, "..", 2))
					continue;

				if (afd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				{
					char next[MAX_PATH];
					if(GetFullPathNameA(lpszFileName, MAX_PATH, next, &part) == 0){ return FALSE; }
					strcpy(part, afd.cFileName);
					strcat(next, "\\");
					strcat(next, name);

					__searchFilesA(next, lpSearchFunc, pUserData, TRUE);
				}
			}
			while (FindNextFileA(hSearch, &afd));

			FindClose (hSearch); 
	}

	if ((hSearch = FindFirstFileA(lpszFileName, &afd)) == INVALID_HANDLE_VALUE)
	{   
		return TRUE; 
	}

	do
	if (!(afd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
	{
		char file[MAX_PATH];
		if(GetFullPathNameA(lpszFileName, MAX_PATH, file, &part) == 0) return FALSE;
		strcpy(part, afd.cFileName);

		lpSearchFunc(&file[0], pUserData );
	}
	while (FindNextFileA(hSearch, &afd)); 
	FindClose (hSearch); 


	return TRUE;
}


BOOL  __searchFilesW(WCHAR* lpszFileName, __TFUNCFOUNDFILEW lpSearchFunc,  void* pUserData,  BOOL bInnerFolders)
{
	LPWSTR part;
	WCHAR tmp[MAX_PATH];
	WCHAR name[MAX_PATH];

	HANDLE hSearch = NULL;
	WIN32_FIND_DATAW  wfd ;
	memset(&wfd, 0, sizeof(WIN32_FIND_DATAW));


	if(bInnerFolders)
	{
		if(GetFullPathNameW(lpszFileName, MAX_PATH, tmp, &part) == 0) 
		{   
			return FALSE; 
		}

		wcscpy(name, part);
		wcscpy(part, L"*.*");

		wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
		if (!((hSearch = FindFirstFileW(tmp, &wfd)) == INVALID_HANDLE_VALUE))
			do
			{
				if (!wcsncmp(wfd.cFileName, L".", 1) || !wcsncmp(wfd.cFileName, L"..", 2))
					continue;

				if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
				{
					WCHAR next[MAX_PATH];
					if(GetFullPathNameW(lpszFileName, MAX_PATH, next, &part) == 0){  return FALSE; }
					wcscpy(part, wfd.cFileName);
					wcscat(next, L"\\");
					wcscat(next, name);

					__searchFilesW(next, lpSearchFunc, pUserData,   TRUE);
				}
			}
			while (FindNextFileW(hSearch, &wfd));

			FindClose (hSearch);
	}

	if ((hSearch = FindFirstFileW(lpszFileName, &wfd)) == INVALID_HANDLE_VALUE)
	{  
		return TRUE; 
	} 

	do
	if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
	{
		WCHAR file[MAX_PATH];
		if(GetFullPathNameW(lpszFileName, MAX_PATH, file, &part) == 0) return FALSE;
		wcscpy(part, wfd.cFileName);

		lpSearchFunc(&file[0], pUserData );
	}
	while (FindNextFileW(hSearch, &wfd)); 
	FindClose (hSearch); 


	return TRUE;
}

 

static void __on_found_file_a( const CHAR*  lpszFileName, void* pUserData )
{
	std::vector<string>* pdest = ( std::vector<string>* )pUserData;
	pdest->push_back( string(lpszFileName) );
}

void search_files(std::vector<string>&  dest, const string&  directory_,  string&  extentions, bool includeSubFolders)
{
	assert( directory_.length() );
	assert( extentions.length() );
 
	std::vector<string> vexts;
	string item;
	for( size_t c=0; c<extentions.length(); ++c )
	{
		if( extentions[c] == ';' )
		{
			if( item.length() ) { vexts.push_back( item  ); item.clear(); continue; }
		}

		item += extentions[c];	
	}

	if( item.length() ) { vexts.push_back( item  ); item.clear(); }
	 
	for(size_t c=0; c<vexts.size(); c++)
	{
		string arg = directory_ + string("*.") + vexts[c];
		__searchFilesA( (CHAR*) arg.c_str(), __on_found_file_a, (void*)&dest, includeSubFolders );
	}



}

static void __on_found_file_w( const WCHAR*  lpszFileName, void* pUserData )
{
	std::vector<wstring>* pdest = ( std::vector<wstring>* )pUserData;
	pdest->push_back( wstring(lpszFileName) );
}

void search_files(std::vector<wstring>& dest, const wstring& directory_, wstring&  extentions, bool includeSubFolders)
{
	assert( directory_.length() );
	assert( extentions.length() );

	std::vector<wstring> vexts;
	wstring item;
	for( size_t c=0; c<extentions.length(); ++c )
	{
		if( extentions[c] == L';' )
		{
			if( item.length() ) { vexts.push_back( item  ); item.clear(); continue; }
		}

		item += extentions[c];	
	}

	if( item.length() ) { vexts.push_back( item  ); item.clear(); }

	for(size_t c=0; c<vexts.size(); c++)
	{
		wstring arg = directory_ + wstring(L"*.") + vexts[c];
		__searchFilesW( (WCHAR*) arg.c_str(), __on_found_file_w, (void*)&dest, includeSubFolders );
	}


}


bool is_file_exests( const string&  filename )
{
	return ::GetFileAttributesA( (LPCSTR)filename.c_str()) != DWORD(-1);
}

bool is_file_exests( const wstring& filename )
{
	return ::GetFileAttributesW( (LPCWSTR)filename.c_str()) != DWORD(-1);
}

bool is_directory_exests( const string&  directory_ )
{
	int rv = GetFileAttributesA( directory_.c_str() );
	if(rv == -1) return false;
	return ( (rv & FILE_ATTRIBUTE_DIRECTORY) != 0);
}

bool is_directory_exests( const wstring& directory_ )
{
	int rv = GetFileAttributesW( directory_.c_str() );
	if(rv == -1) return false;
	return ( (rv & FILE_ATTRIBUTE_DIRECTORY) != 0);
}


string  get_extention( const string&  filename )
{
	if(filename.length() == 0) return string();
	for(size_t c=filename.length()-1; c>=0; c--)
	{
		if(filename[c] == '.')
		{
			return filename.substr( c+1, filename.length() );
		}
	}

	return string();
}
  
wstring  get_extention( const wstring&  filename )
{
	if(filename.length() == 0) return wstring();
	for(size_t c=filename.length()-1; c>=0; c--)
	{
		if(filename[c] == L'.')
		{
			return filename.substr( c+1, filename.length() );
		}
	}

	return wstring();
}


string  set_extention(const string&  filename, const string& new_extention)
{
	if(filename.length()==0) return string();

	for(size_t c=filename.length()-1; c>=0; c-- )
	{
		if ( filename[c] == '.' )
		{
			string res = filename.substr(  0,  c+1  );
			res += new_extention;
			return res;
		}
	}

	return string();
}

wstring set_extention(const wstring& filename, const wstring& new_extention)
{
	if(filename.length()==0) return wstring();

	for(size_t c=filename.length()-1; c>=0; c-- )
	{
		if ( filename[c] == L'.' )
		{
			wstring res = filename.substr(  0,  c+1  );
			res += new_extention;
			return res;
		}
	}

	return wstring();
}

string  get_directory(const string&  fullpath)
{
	if(fullpath.length()==0) return string();

	for (size_t c = fullpath.length()-1; c >= 0; c--) 
	{
		if (  (fullpath [c] == '\\') || (fullpath [c] == L'/')  ) 
		{
			string res =  fullpath.substr( 0, c+1 );
			return res;
		}
	}

	return string();
}

wstring  get_directory(const wstring&  fullpath)
{
	if(fullpath.length()==0) return wstring();

	for( size_t c = fullpath.length()-1; c >= 0; c-- ) 
	{
		if (  (fullpath [c] == L'\\') || (fullpath [c] == L'/')  ) 
		{
			wstring res =  fullpath.substr( 0, c+1 );
			return res;
		}
	}

	return wstring();
}


string  get_filename(const string&  fullpath)
{
	if(fullpath.length()==0) return string();

	for( size_t c = fullpath.length()-1; c >= 0; c-- ) 
	{
		if (  (fullpath [c] == '\\') || (fullpath [c] == L'/')  ) 
		{
			string res =  fullpath.substr( c+2, fullpath.length() );
			return  res;
		}
	}

	return string();
}

wstring get_filename(const wstring&  fullpath)
{
	if(fullpath.length()==0) return wstring();

	for( size_t c = fullpath.length()-1; c >= 0; c-- ) 
	{
		if (  (fullpath [c] == L'\\') || (fullpath [c] == L'/')  ) 
		{
			wstring res =  fullpath.substr( c+2, fullpath.length() );
			return  res;
		}
	}

	return wstring();
}


void create_directory( string&  directory_ ) throw (std::runtime_error)
{
	if(is_directory_exests(directory_)) return;
	if(! CreateDirectoryA(directory_.c_str(), NULL))
	{
		DWORD dwErr =	GetLastError();
		std::ostringstream oss;
		oss << "Error call CreateDirectory. code ";
		oss << dwErr;
		throw std::runtime_error(oss.str());
	}
 
}

void create_directory( wstring& directory_ ) throw (std::runtime_error)
{
	if(is_directory_exests(directory_)) return;
	if(! CreateDirectoryW(directory_.c_str(), NULL))
	{
		DWORD dwErr =	GetLastError();
		std::ostringstream oss;
		oss << "Error call CreateDirectory. code ";
		oss << dwErr;
		throw std::runtime_error(oss.str());
	}
}

 

void split( string&  directory_, string& file_, string& extention_,  const string& fullpath )
{
	size_t nPointPos = 0-1;
	size_t nSlashPos = 0-1;
	for( size_t c = fullpath.length()-1; c >= 0; c-- ) 
	{
		if(c == 0xffffffff) break; 
 
		if(fullpath[c] == '.')
		{
			nPointPos = c;
			break;
		}
	}

	for( size_t c = fullpath.length()-1; c >= 0; c-- ) 
	{
		if(c == 0xffffffff) break; 

		if( (fullpath[c] == '\\') || (fullpath[c] == '/') )
		{
			nSlashPos = c;
			break;
		}
	}
 

	extention_.clear();
	if( nPointPos != 0-1 )
	{
		extention_ = fullpath.substr( nPointPos+1, fullpath.length() );
	}

	directory_.clear();
	if( nSlashPos != 0-1 )
	{
		directory_ = fullpath.substr( 0 , nSlashPos+1 );
	}

	file_.clear();
	if( nPointPos==0-1 && nSlashPos==0-1 )
	{
		file_ = fullpath;
		return;
	}

	if( nPointPos!=0-1 && nSlashPos!=0-1 )
	{
		file_ = fullpath.substr( nSlashPos+1, nPointPos - nSlashPos - 1 );
	}
 
	if( nPointPos==0-1 )
	{
		file_ = fullpath.substr( nSlashPos + 1, fullpath.length() );
	}
	else
	{
		file_ = fullpath.substr( 0, fullpath.length() );
	}


}

void split( wstring& directory_, wstring& file_, wstring& extention_, const wstring& fullpath )
{
	size_t nPointPos = 0-1;
	size_t nSlashPos = 0-1;
	for( size_t c = fullpath.length()-1; c >= 0; c-- ) 
	{
		if(c == 0xffffffff) break; 

		if(fullpath[c] == L'.')
		{
			nPointPos = c;
			break;
		}
	}

	for( size_t c = fullpath.length()-1; c >= 0; c-- ) 
	{
		if(c == 0xffffffff) break; 

		if( (fullpath[c] == L'\\') || (fullpath[c] == L'/') )
		{
			nSlashPos = c;
			break;
		}
	}
 
	extention_.clear();
	if( nPointPos != 0-1 )
	{
		extention_ = fullpath.substr( nPointPos+1, fullpath.length() );
	}

	directory_.clear();
	if( nSlashPos != 0-1 )
	{
		directory_ = fullpath.substr( 0 , nSlashPos+1 );
	}

	file_.clear();
	if( nPointPos==0-1 && nSlashPos==0-1 )
	{
		file_ = fullpath;
		return;
	}

	if( nPointPos!=0-1 && nSlashPos!=0-1 )
	{
		file_ = fullpath.substr( nSlashPos+1, nPointPos - nSlashPos - 1 );
	}

	if( nPointPos==0-1 )
	{
		file_ = fullpath.substr( nSlashPos + 1, fullpath.length() );
	}
	else
	{
		file_ = fullpath.substr( 0, fullpath.length() );
	}

}


void save_to_file(const void* data, const size_t len, const string&  filename) throw (std::runtime_error)
{
	FILE* f = fopen(filename.c_str(), "w+b");
	if ( !f ) 
	{
		throw std::runtime_error("error open file");
	}

	if ( fwrite(data, 1, len, f) != len ) 
	{

		fclose(f);
		throw std::runtime_error("error write data");
	}

	fflush(f);
	fclose(f);
}

void save_to_file(const void* data, const size_t len, const wstring& filename) throw (std::runtime_error)
{
	FILE* f = _wfopen(filename.c_str(), L"w+b");
	if ( !f ) 
	{
		throw std::runtime_error("error open file");
	}

	if ( fwrite(data, 1, len, f) != len ) 
	{

		fclose(f);
		throw std::runtime_error("error write data");
	}

	fflush(f);
	fclose(f);
}



void save_to_file(const string& txt, const string&  filename)  throw (std::runtime_error)
{
	save_to_file(txt.c_str(), txt.length(), filename);
}

void save_to_file(const string& txt, const wstring& filename)  throw (std::runtime_error)
{
	save_to_file(txt.c_str(), txt.length(), filename);
}



string  get_exe_fullpath_ansi()
{
	CHAR temp[MAX_PATH];
	if( !GetModuleFileNameA(NULL, temp, MAX_PATH) )
	{
		throw std::runtime_error("error call GetModuleFileNameA");
	}

	return string(temp);
}

wstring get_exe_fullpath_wide()
{
	WCHAR temp[MAX_PATH];
	if( !GetModuleFileNameW(NULL, temp, MAX_PATH) )
	{
		throw std::runtime_error("error call GetModuleFileNameW");
	}

	return wstring(temp);
}


string  get_exe_directory_ansi()
{
	string temp = get_exe_fullpath_ansi();
	temp = get_directory(temp);
	return temp;
}

wstring get_exe_directory_wide()
{
	wstring temp = get_exe_fullpath_wide();
	temp = get_directory(temp);
	return temp;
}


string  get_module_directory_ansi( HMODULE hm)
{
	CHAR temp[MAX_PATH];
	if( !GetModuleFileNameA(hm, temp, MAX_PATH) )
	{
		throw std::runtime_error("error call GetModuleFileNameA");
	}

	string res(temp);
	res = get_directory(temp);
	return temp;
}

wstring get_module_directory_wide( HMODULE hm)
{
	WCHAR temp[MAX_PATH];
	if( !GetModuleFileNameW(hm, temp, MAX_PATH) )
	{
		throw std::runtime_error("error call GetModuleFileNameW");
	}

	wstring res(temp);
	res = get_directory(temp);
	return temp;
}


string get_fullpath( const string& filename )
{
	CHAR temp[MAX_PATH];
	if(!GetFullPathNameA( filename.c_str(), MAX_PATH, temp, NULL ) )
	{
		throw std::runtime_error("error call GetFullPathName");
	}

	return string(temp);
}

wstring get_fullpath( const wstring& filename )
{
	WCHAR temp[MAX_PATH];
	if(!GetFullPathNameW( filename.c_str(), MAX_PATH, temp, NULL ) )
	{
		throw std::runtime_error("error call GetFullPathName");
	}

	return wstring(temp);
}



string get_shortpath( const string& src )
{
	CHAR buf[MAX_PATH] = {'\0'};
	if( !GetShortPathNameA( src.c_str(), buf, MAX_PATH ) )
	{
		throw std::runtime_error("error call GetShortPathName");
	}

	return string(buf);	 
}


wstring get_shortpath( const wstring& src )
{
	WCHAR buf[MAX_PATH] = {L'\0'};
	if( !GetShortPathNameW( src.c_str(), buf, MAX_PATH ) )
	{
		throw std::runtime_error("error call GetShortPathName");
	}

	return wstring(  buf );	 
}




   

bool set_directory_up( string& directory_ )
{

	if(directory_.length() == 0) return false;
	if(directory_.length() <= 3) return false;

	size_t nbegin =  directory_.length()-1;
	if( (directory_[ directory_.length()-1 ] == '\\') || (directory_[ directory_.length()-1 ] == '/') )
	{
		nbegin--;
	}

	for(size_t c=nbegin; c>=0; c--)
	{
		if( (directory_[c] == '\\') || directory_[c] == '/' )
		{
			string temp = directory_.substr( 0 , c+1 );
			directory_ = temp;
			return true;
		}
	}

	return false;
}


bool set_directory_up( wstring& directory_ )
{

	if(directory_.length() == 0) return false;
	if(directory_.length() <= 3) return false;

	size_t nbegin =  directory_.length()-1;
	if( (directory_[ directory_.length()-1 ] == L'\\') || (directory_[ directory_.length()-1 ] == L'/') )
	{
		nbegin--;
	}

	for(size_t c=nbegin; c>=0; c--)
	{
		if( (directory_[c] == L'\\') || directory_[c] == L'/' )
		{
			wstring temp = directory_.substr( 0 , c+1 );
			directory_ = temp;
			return true;
		}
	}

	return false;
}
 



void load_from_file_binary( std::vector<BYTE>& dest, const string& filename ) throw(std::runtime_error)
{
	FILE* file = fopen(filename.c_str(), "r+b");
	if(!file)
	{
		throw std::runtime_error("error open file");
	}

	size_t num=0;
	fseek(file, 0 , SEEK_END );
	num = ftell(file);
	fseek(file,0, SEEK_SET );

	dest.reserve(num);
	dest.assign(num, 0);

	fread( &dest[0], 1, num , file);
	fclose(file);
}
 

void load_from_file_binary( std::vector<BYTE>& dest, const wstring& filename ) throw(std::runtime_error)
{
	FILE* file = _wfopen(filename.c_str(), L"r+b");
	if(!file)
	{
		throw std::runtime_error("error open file");
	}

	size_t num=0;
	fseek(file, 0 , SEEK_END );
	num = ftell(file);
	fseek(file,0, SEEK_SET );

	dest.reserve(num);
	dest.assign(num, 0);

	fread( &dest[0], 1, num , file);
	fclose(file);
}

void load_from_file(string& dest, const string&  filename)  throw (std::runtime_error)
{
	std::vector<BYTE> bin;
	load_from_file_binary(bin, filename);
	bin.push_back('\0');
	dest = (char*) &bin[0];
}

void load_from_file(string& dest, const wstring& filename)  throw (std::runtime_error)
{
	std::vector<BYTE> bin;
	load_from_file_binary(bin, filename);
	bin.push_back('\0');
	dest = (char*) &bin[0];
}

bool search_directory_up( string&  dest, const string&  sub_directory_, const string&  start_directory_fullname ) 
{
	dest.clear();
	string curr = start_directory_fullname;
	while(true)
	{
		if( is_directory_exests( curr + sub_directory_ ) )
		{
			dest = curr + sub_directory_;
			return true;
		}

		if( !set_directory_up(curr) )
		{
			return false;
		}
	}

	return false;
}

bool search_directory_up( wstring& dest, const wstring& sub_directory_, const wstring& start_directory_fullname ) 
{
	dest.clear();
	wstring curr = start_directory_fullname;
	while(true)
	{
		if( is_directory_exests( curr + sub_directory_ ) )
		{
			dest = curr + sub_directory_;
			return true;
		}

		if( !set_directory_up(curr) )
		{
			return false;
		}
	}

	return false;
}






}



#endif // WIN32